package com.example.demo.tool;

import com.github.javaparser.StaticJavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import org.springframework.data.repository.init.ResourceReader;

import java.io.*;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;

public class CodeRegularityUtil {
    private static final Pattern CAMEL_CASE_PATTERN = Pattern.compile("^[a-z]+([A-Z][a-z0-9]+)*$");
    private static final Pattern SNAKE_CASE_PATTERN = Pattern.compile("^[a-z]+(_[a-z0-9]+)*$");
    private static final int MAX_LINE_LENGTH = 120; // 最大行长度
    private static final int INDENTATION_SPACES = 4; // 缩进空格数

    private static final Set<String> dictionary = new HashSet<>(); // 字典

    static {

        try {

            // 获取资源文件的 InputStream
            InputStream inputStream = ResourceReader.class.getClassLoader().getResourceAsStream("word.txt");

            if (inputStream == null) {
                System.out.println("文件未找到！");
            }

            // 通过 BufferedReader 读取文件内容
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    String[] words = line.trim().toLowerCase().split(" ");
                    for (String word : words) {
                        dictionary.add(word);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        System.out.println("dictionary.size : " + dictionary.size());
    }

    public static void main(String[] args) {
        String code =
                "";
        System.out.println(new CodeRegularityUtil().analyzeCode(code,"C++"));
    }

    public static int analyzeCode(String code,String language) { // 分析代码
        int score = 100; // 初始分数
        int sum = 0; // 不符合规范的地方的个数
        String[] lines = code.split("\n"); // 将代码分割成行

        if(language.equals("Python")){
            sum = isIndentationConsistentForPython(code,sum);
            sum = isMultipleStatements(code,sum);
            sum = isLineLengthValid(code,sum);
        }else if(language.equals("Java") || language.equals("C++")){
            if(language.equals("Java")){
                sum = checkName(code,sum);
            }
            sum = isMultipleStatements(code,sum);
            sum = isIndentationConsistentForJavaOrC(code,sum);
            sum = isLineLengthValid(code,sum);
        }else {
            //TODO 处理其他语言
            sum = 1;
        }
        score = score * (lines.length - sum) / lines.length;
        return Math.max(score, 60); // 确保分数不低于0
    }

    /**
     * 根据给定的代码字符串和分数，解析代码并提取类名和函数名
     * 此方法主要用于演示如何解析Java代码字符串，并提取其中的类名和函数名
     * 不会对代码进行编译或执行，只是进行语法层面的解析和信息提取
     *
     * @param code   一个字符串，代表Java代码
     * @return 返回输入时的分数此方法不进行任何分数相关的处理，因此原样返回
     */
    public static int checkName(String code, int sum) {

        try {
            // 解析代码
            CompilationUnit cu = StaticJavaParser.parse(code);

            // 提取类名
            for (ClassOrInterfaceDeclaration clazz : cu.findAll(ClassOrInterfaceDeclaration.class)) {
                // 类名好像是默认大写
    //            String name = clazz.getNameAsString();
    ////            System.out.println(name);
    //            if(!isValidName(name)) {
    //                System.out.println(name);
    //                sum++;
    //            }
                // 提取函数名
                for (MethodDeclaration method : clazz.getMethods()) {
                    String methodName = method.getNameAsString();
                    if(!isValidName(methodName)){
                        sum++;
                    }
    //                System.out.println(methodName);
                }
            }
        } catch (Exception e) {
            System.err.println("解析Java代码时遇到语法错误: " + e.getMessage());
        } finally {
            return sum;
        }
    }

    /**
     * 检查名称是否有效
     * 此方法定义有效的名称为：既可以是驼峰命名法，也可以是蛇形命名法，并且名称中的每个单词都应是有效的英文单词
     *
     * @param name 要检查的名称
     * @return 如果名称有效，则返回true；否则返回false
     */
    public static boolean isValidName(String name) {
        if(name.isEmpty()) return true;
        // 检查名称是否符合驼峰命名法或蛇形命名法，并且每个单词都是有效的英文单词
        return (CAMEL_CASE_PATTERN.matcher(name).matches() || SNAKE_CASE_PATTERN.matcher(name).matches())
                && areValidEnglishWords(name);
    }

    /**
     * 检查名称中的每个单词是否都是有效的英文单词
     *
     * @param name 要检查的名称
     * @return 如果名称中的每个单词都是有效的英文单词，则返回true；否则返回false
     */
    private static boolean areValidEnglishWords(String name) {
        // 使用正则表达式分割名称中的每个单词，正则表达式匹配大写字母前的位置（用于驼峰命名法）或下划线（用于蛇形命名法）
        String[] words = name.split("(?<!^)(?=[A-Z])|_");
        for (String word : words) {
            // 检查每个单词是否在字典中，不在字典中的单词被认为是无效的
            if (!dictionary.contains(word.toLowerCase())) {
                return false;
            }
        }
        return true;
    }

    /**
     * 检查java和C/C++代码中的缩进是否一致.
     *
     * @param code 一段字符串形式的代码
     * @return 如果代码中的缩进一致，则返回true；否则返回false
     */
    public static int isIndentationConsistentForJavaOrC(String code,int sum) {
        // 将代码按行分割
        String[] lines = code.split("\n");
        // 预期的缩进量，初始为0
        int expectedIndentation = 0;

        boolean inBlockComment = false;

        int i = 0;
        // 遍历每行代码
        for (String line : lines) {
            if(line.isEmpty()) continue;
            i++;
//            System.out.println(i + "      " + line);
            // 去除行首和行尾的空白字符
            String trimmedLine = line.trim();

            // 处理单行注释和空行
            if (trimmedLine.isEmpty() || trimmedLine.startsWith("//")) {
                continue;
            }

            // 处理多行注释
            if (trimmedLine.startsWith("/*") || inBlockComment) {
                int commentEndIndex = trimmedLine.indexOf("*/");
                if (commentEndIndex >= 0) {
                    inBlockComment = false;
                    continue;
                } else {
                    inBlockComment = true;
                    continue;
                }
            }

            // 计算当前行的实际缩进量
            int actualIndentation = getLeadingSpaces(line);

            // 如果当前行以“}”开头，预期缩进量减少
            if (trimmedLine.startsWith("}")) {
                expectedIndentation -= INDENTATION_SPACES;
            }
//            System.out.println("ex : " + expectedIndentation);
            // 如果当前行的实际缩进量与预期缩进量不一致，返回false
            if (actualIndentation != expectedIndentation) {
//                System.out.printf("第多少行 %s , 实际缩进 %s , 期待缩进 %s %n" , i, actualIndentation, expectedIndentation);
                sum++;
            }

            // 如果当前行以“{”结尾，预期缩进量增加
            // 如果“{” 后面打注释，会导致规范性出很多错
            if (trimmedLine.endsWith("{")) {
                expectedIndentation += INDENTATION_SPACES;
            }

        }
        System.out.println("代码缩进错误 ： " + sum);
        // 如果所有行的缩进都一致，返回true
        return sum;
    }

    /**
     * 检查Python代码中的缩进是否一致.python判断如果出现冒号，下一行必须向后缩进4格
     *
     * @param code 一段字符串形式的代码
     * @return 如果代码中的缩进一致，则返回true；否则返回false
     */
    public static int isIndentationConsistentForPython(String code,int sum) {
        // 将代码按行分割
        String[] lines = code.split("\n");
        // 预期的缩进量，初始为0
        int expectedIndentation = 0;
        // 判断该行的上一行是否是 : 结尾
        boolean lastLineWasColon = false;

        for (int i = 0; i < lines.length; i++) {
            String line = lines[i];
            if(line.isEmpty()) continue;

            // 去除行首和行尾的空白字符
            String trimmedLine = line.trim();

            if(trimmedLine.startsWith("#")){
                continue;
            }

            if(trimmedLine.startsWith("'''")){
                while (true){
                    i++;
                    trimmedLine = lines[i].trim();
                    if(trimmedLine.startsWith("'''")){
                        break;
                    }
                }
            }

            if(trimmedLine.startsWith("\"\"\"")){
                while (true){
                    i++;
                    trimmedLine = lines[i].trim();
                    if(trimmedLine.startsWith("\"\"\"")){
                        break;
                    }
                }
            }

            // 计算当前行的实际缩进量
            int actualIndentation = getLeadingSpaces(line);

            // 如果当前行的实际缩进量与预期缩进量不一致，返回false
            if (actualIndentation != expectedIndentation && lastLineWasColon) {
                sum++;
            }

            expectedIndentation = actualIndentation;

            // 如果当前行以“:”结尾，预期缩进量加4格
            if(trimmedLine.endsWith(":")){
                lastLineWasColon = true;
                expectedIndentation += INDENTATION_SPACES;
            }else {
                lastLineWasColon = false;
            }

        }
        System.out.println("代码缩进错误 ： " + sum);
        return sum;
    }

    /**
     * 如果一行存在多条语句，那么不规范地方加一，如果存在for， 我们就忽略
     * @param code
     * @param sum
     * @return
     */
    public static int isMultipleStatements(String code,int sum) {
        String[] lines = code.split("\n");
        for (String line : lines) {
            int count = 0;
            for (int i = 0; i < line.length(); i++) {
                if(line.charAt(i) == ';') {
                    count++;
                }
            }
            // 说明出现多条语句
            if(count > 1 && line.indexOf("for") > -1) {
                sum++;
            }
        }

        System.out.println("一行出现2条语句错误 ： " + sum);
        return sum;
    }

    /**
     * 计算字符串前导空格的数量.
     *
     * @param line 一行代码
     * @return 前导空格的数量
     */
    private static int getLeadingSpaces(String line) {
        // 空格计数
        int count = 0;
        // 遍历字符串，直到遇到非空格字符
        while (count < line.length() && line.charAt(count) == ' ') {
            count++;
        }
        // 如果缩进为 \t 那么需要重新计算
        int i = 0;
        if(count == 0){
            while (i < line.length() && line.charAt(i) == '\t'){
                count += 4;
                i++;
            }
        }

        // 返回前导空格的数量
        return count;
    }

    /**
     * 检查代码中的所有行是否都不超过最大行长度.
     *
     * 此方法通过分割输入的代码字符串来确定每一行的长度，
     * 然后逐行检查是否超过预定义的最大行长度.
     *
     * @param code 待检查的代码字符串
     * @return 如果所有行的长度都不超过最大行长度，则返回true；否则返回false
     */
    public static int isLineLengthValid(String code,int sum) {
        // 根据换行符分割代码字符串，获取每一行
        String[] lines = code.split("\n");

        // 遍历所有行
        for (String line : lines) {
            if(line.isEmpty()) continue;
            // 如果某一行的长度超过最大行长度
            if (line.length() - getLeadingSpaces(line) > MAX_LINE_LENGTH) {
                // 则返回false，表示代码行长度无效
                sum++;
            }
        }
        System.out.println("代码长度错误 ： " + sum);
        return sum;
    }

}
